import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Ticket {

//这就是资源类，也就是门票资源，是一个类
//对象 = 属性 + 方法  要高内聚，对于门票资源类来说，门票的票数就是属性，默认属性，
// 卖票这一个行为就叫做一个方法，对外提供，可以通过对象调用该方法，实现卖票的功能

    //默认属性50张票
    private int number = 50;

    //定义一个卖票的方法，使用Public修饰，供外部访问
    //加上synchronized锁，保证互斥访问
    //第一种方法
//    public synchronized void sale() {
//        //当票数大于0时，才可以卖出
//        if (number > 0) {
//            String name = Thread.currentThread().getName();
//            System.out.println(name + "卖出" + number-- + "张票，还剩" + number + "张票");
//            //睡眠一下
////            try {
////                TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);
////            }
//        }
//
//    }
    //第二种方式
//    public void sale(){
//        synchronized (this){
//            if(number>0){
//                //卖票
//                System.out.println(Thread.currentThread().getName()+"卖出了"+number--+"张票，还剩："+number+"张票");
////                try {
////                    TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);
////                }
//            }
//        }
//    }
    //第三种方式，使用JUC的lock锁
    Lock lock = new ReentrantLock();//多态
    public void sale(){
        lock.lock();
        try {
            for (int i = 0; i < 50; i++) {
                if(number>0){
                    System.out.println(Thread.currentThread().getName()+"卖出了"+number--+"张票，还剩："+number+"张票");
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);
                    }
                }
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }


    }
}

public class demo_jucPratice {
    public static void main(String[] args) {

        //三个售票员，卖出50张票
        //三个售票员是三个线程，操作同一资源

        //高聚低耦是前提   线程 操作 资源类
        /*
        首先得有线程   和资源类（就是门票），资源类得自带方法，把方法紧紧地聚合在类里，这叫高内聚
        和线程之间是低耦合，是独立的东西，只不过线程要操作资源类，也就是门票
         */

        //通过线程调用方法,要new Runnable接口，实现该接口，重写run方法

        Ticket ticket = new Ticket();
        new Thread(new Runnable() {

            @Override
            public void run() {

                //使用循环
//                for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
 //           }
        },"zml").start();//通过start开启线程
        new Thread(new Runnable() {
            @Override
            public void run() {

                //使用循环
//                for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
  //          }
        },"qx").start();//通过start开启线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //使用循环
 //               for (int i = 0; i < 50; i++) {
                    ticket.sale();
                }
 //           }
        },"jk").start();//通过start开启线程

    }
}
